#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>

struct list
{
  struct list* next;
  int data;
};

struct list* head;

pthread_mutex_t lock;
pthread_cond_t cond;

void* consumer(void*);
void* producer(void*);

int main(int argc,char** argv)
{
  srand(time(NULL));
  int ret;
  ret = pthread_mutex_init(&lock,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutex_init is fail,%s\n",strerror(ret));
    exit(-1);
  }
  ret = pthread_cond_init(&cond,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_cond_init is fail,%s\n",strerror(ret));
    exit(-1);
  }
  
  pthread_attr_t attr;
  ret = pthread_attr_init(&attr);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_attr_init is fail,%s\n",strerror(ret));
    exit(-1);
  }
  ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_attr_setdetachstate is fail,%s\n",strerror(ret));
    exit(-1);
  }
  
  pthread_t tid;
  head = malloc(sizeof(struct list));
  head->next = NULL;
  ret = pthread_create(&tid,&attr,producer,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_create is fail,%s\n",strerror(ret));
    exit(-1);
  }

  ret = pthread_create(&tid,&attr,consumer,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_create is fail,%s\n",strerror(ret));
    exit(-1);
  }
  ret = pthread_attr_destroy(&attr);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_attr_destroy is fail,%s\n",strerror(ret));
    exit(-1);
  }
  ret = pthread_mutex_destroy(&lock);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutux_destory is fail,%s\n",strerror(ret));
    exit(-1);
  }

  ret= pthread_cond_destroy(&cond);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_cond_destory is fail,%s\n",strerror(ret));
    exit(-1);
  }
  pthread_exit((void*)0);
}

void* consumer(void* data)
{
  struct list* new_node;
  while(1)
  {
    pthread_mutex_lock(&lock);

    while(head->next == NULL)
    {
      pthread_cond_wait(&cond,&lock);
    }
    
    new_node = head->next;
    printf("consumer is %d\n",new_node->data);
    
    head->next = new_node->next;
    free(new_node);
    pthread_mutex_unlock(&lock);
    sleep(rand()%2);
  }
}
void* producer(void* data)
{
  struct list* new_node;
  int ret;
  while(1)
  {
    new_node = malloc(sizeof(struct list));
    ret = pthread_mutex_lock(&lock);
    new_node->data = rand()%10000;
    printf("producer %d\n",new_node->data);
    new_node->next = head->next;
    head->next = new_node;

    pthread_mutex_unlock(&lock);
    pthread_cond_signal(&cond);
    sleep(rand()%3);
  }
  return NULL;
}
